"""
with EXPR as VAR:
    BLOCK
上下文表达式：with EXPR as VAR
上下文管理器：EXPR
资源对象：VAR
"""
import contextlib
import sqlite3
import time

with open("test.txt", encoding="utf-8") as f:
    print(f.readline())
print("1.什么是上下文管理器")
print("对于上下文表达式：with EXPR as VAR,EXPR就是上下文管理器")


class SqlExpr:
    """
    在一个类里，实现了__enter__和__exit__的方法，这个类的实例就是一个上下文管理器
    """
    def __init__(self, db_path, select_sql):
        """
        初始化参数
        :param db_path: sqlite数据库路径
        :param select_sql: 查询sql语句
        """
        self.db = None
        self.db_path = db_path
        self.select_sql = select_sql

    def __enter__(self):
        """
        连接数据库
        :return:class对象
        """
        self.db = sqlite3.connect(self.db_path)
        print("\t\t==connect sqlite==")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """
        关闭数据库
        :param exc_type 异常类型
        :param exc_val 异常值
        :param exc_tb 错误信息
        :return:True, 告诉python解释器，这个异常我们已经捕获了，不需要再往外抛了。
        """
        self.db.close()
        print("\t\t==close sqlite==")
        return True

    def show(self):
        """
        查询打印语句
        """
        try:
            cursor = self.db.cursor()
            cursor.execute(self.select_sql)
            for data in cursor:
                print("\t\t", data)
            print(1/0)
        except AttributeError:
            print(f"\t\t无法连接数据库，参数self.db为{self.db}")


print("\t1.1实例化对象调用函数:")
# sql = SqlExpr("TODO.db", "select * from todo limit 1")
# sql.show()


print("\t1.2使用上下文管理器-SqlExpr")
with SqlExpr("TODO.db", "select * from todo limit 1") as res:
    res.show()

print('在上面，SqlExpr("TODO.db", "select * from todo limit 1")就是上下文管理器')

print("""2.正确使用上下文管理器
\t2.1使用’装饰器‘，把函数对象变成一个上下文管理器""")


def out_func(text):
    def in_func():
        print(text)
        return in_func
    return in_func


func = out_func("\t\t2.1.1装饰器的性质————闭包")
func()

print("\t\t2.1.2使用装饰器")


def time_log(func):
    def wrapper(text, format):
        print(f"{format}{time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())} {func.__name__} executed")
        return func(text, format)
    return wrapper


@time_log
def main_func(text, format):
    print(format, text)
    return True


main_func("execute func", "\t\t\t")  # time_log(main_func)


# yield和生成器
def fab(max):
    """
    一个数列（斐波那契）
    除第一个和第二个数外，任意一个数都可由前两个数相加得到
    :param max:
    :return:
    """
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1


for n in fab(5):
    print(n)

print("==")


class Fab:
    def __init__(self, max):
        self.max = max
        self.n = 0
        self.a = 0
        self.b = 1

    def __next__(self):

        self.a, self.b = self.b, self.a + self.b
        self.n = self.n + 1
        if self.n > self.max:
            raise StopIteration
        return self.a

    def __iter__(self):
        return self


for i in Fab(5):
    print(i)


@contextlib.contextmanager
def sql_func(db_path, select_sql):
    # __enter__
    db = sqlite3.connect(db_path)
    cursor = db.cursor()
    cursor.execute(select_sql)
    print("==connect sqlite==")

    try:
        yield cursor
    except Exception as e:
        print(f'the Exception was thrown{e}')
    finally:
        # __exit__
        db.close()
        print("==close sqlite==")
        return


print("++++")


with sql_func('TODO.db', "select * from todo limit 1") as cursor:
    for data in cursor:
        1/0
        print(data)





